import type { App, Plugin } from 'vue'
import { isString, isObject } from '../is'

export const withInstall = <T>(component: T, alias?: string) => {
  const comp = component as any
  comp.install = (app: App) => {
    app.component(comp.name || comp.displayName || comp.__name, component)
    if (alias) {
      app.config.globalProperties[alias] = component
    }
  }
  return component as T & Plugin
}

/** 忽略开头的星号(*) */
export function ignoreStartAsterisk(val) {
  if (!isString(val)) {
    return val
  }
  let i = 0
  while (i < val.length && val[i] === '*') {
    i++
  }
  return val.slice(i)
}

/** 转换事件名，将事件名的首字母大写，并添加 on 前缀 */
export function addOnPrefix(eventName: string) {
  if (!isString(eventName)) {
    return eventName
  }
  return `on${eventName.charAt(0).toUpperCase()}${eventName.slice(1)}`
}

/** 转换事件对象，将事件名的首字母大写，并添加 on 前缀 */
export function addOnPrefixByEventObj(eventsObj: Recordable) {
  const newObj = {}
  if (!isObject(eventsObj)) return newObj
  Object.keys(eventsObj).forEach((key) => {
    const camelCaseKey = addOnPrefix(key)
    newObj[camelCaseKey] = eventsObj[key]
  })
  return newObj
}

/** 获取列表中指定的项 */
export const getListItem = <T extends Recordable>(
  list: T[],
  value: any,
  key = 'value',
  isStrict = false
): T | undefined => {
  return list.find((item) => (isStrict ? item[key] === value : item[key] == value))
}

/**
 * 时间转换
 */
export const convertTimeUnit = (
  time,
  fromUnit: 'ms' | 's' | 'm' | 'h',
  toUnit: 'ms' | 's' | 'm' | 'h',
  precision = 2
) => {
  if (time === null) {
    return null
  }

  const unitRates = {
    ms: 1,
    s: 1000,
    m: 60 * 1000,
    h: 60 * 60 * 1000
  }

  const validUnits = Object.keys(unitRates)
  if (!validUnits.includes(fromUnit)) {
    throw new Error(`无效的原始单位: ${fromUnit}，请使用以下单位: ${validUnits.join(', ')}`)
  }
  if (!validUnits.includes(toUnit)) {
    throw new Error(`无效的目标单位: ${toUnit}，请使用以下单位: ${validUnits.join(', ')}`)
  }

  const ms = time * unitRates[fromUnit]
  const converted = ms / unitRates[toUnit]

  const factor = Math.pow(10, precision)
  return Math.round(converted * factor) / factor
}
